home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 November: Tool Chest / Dev.CD Nov 00 TC Disk 1.toast / Sample Code / Archive / Games / UniversalHIDModuleTest / UHIDTest.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-09-28  |  48.3 KB  |  1,836 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        UHIDTest.c
  3.  
  4.     Contains:    xxx put contents here xxx
  5.  
  6.     Version:    xxx put version here xxx
  7.  
  8.     Copyright:    © 1999 by Apple Computer, Inc., all rights reserved.
  9.  
  10.     File Ownership:
  11.  
  12.         DRI:                xxx put dri here xxx
  13.  
  14.         Other Contact:        xxx put other contact here xxx
  15.  
  16.         Technology:            xxx put technology here xxx
  17.  
  18.     Writers:
  19.  
  20.         (BWS)    Brent Schorsch
  21.  
  22.     Change History (most recent first):
  23.  
  24.        <SP6>     3/20/99    BWS        Update to lastest HIDOpenReportDescriptor API
  25.        <SP5>      3/7/99    BWS        Add Simulate ISp enumeration - similar code to ISp driver
  26.        <SP4>      3/7/99    BWS        Print out caps usage page and usage. Print all usages in hex
  27.        <SP3>      3/7/99    BWS        Implemented get capabilities and print parsed data
  28.        <SP2>      3/5/99    BWS        Added HIDLib calls
  29. */
  30.  
  31. #include <MacTypes.h>
  32.  
  33. #include <SIOUX.h>
  34. #include <LowMem.h>
  35. #include <USB.h>
  36. #include <InputSprocket.h>
  37. #include "HID.h"
  38. //#include "UniversalHIDModule.h"
  39.  
  40. #include <stdarg.h>
  41. #include <stdio.h>
  42. #include <stdlib.h>
  43. #include <string.h>
  44.  
  45. //#include "HIDPriv.h"
  46.  
  47. // extern protos
  48. extern void PrintHIDReport(UInt8 * reportDesc, UInt32 length);
  49.  
  50.  
  51. // globals
  52.  
  53. // quit state
  54. Boolean                            gShouldQuit = false;
  55.  
  56. // steps of process
  57. SInt32                             gStep;
  58. char                             gStepId[255];
  59.  
  60. // 'safe' (delayed) printf
  61. enum { kPrintfBufferSize        = 1024 * 32 };
  62.  
  63. UInt32                            gMaxPacketSize;
  64. char                            gPrintfBuffer1[kPrintfBufferSize + 256];
  65. char                            gPrintfBuffer2[kPrintfBufferSize + 256];
  66. char *                            gInsertPrintfBuffer;
  67. char *                            gFreePrintfBuffer;
  68. UInt32                            gInsertIndex = 0;
  69.  
  70. enum
  71. {
  72.     kPrint_AsHex            = 1,
  73.     kPrint_AsBinary,
  74.     kPrint_ParseButtons,
  75.     kPrint_ParseBoth,
  76.     kPrint_SimulateISp
  77. };
  78.  
  79. UInt32                            gPrint_AsType;
  80.  
  81. // HID stuff
  82.  
  83. // these constants are from the USB HID Usage Table spec
  84. enum
  85. {
  86.     kHIDPage_Generic        = 1,
  87.     kHIDUsage_Joystick        = 0x04,
  88.     kHIDUsage_Gamepad        = 0x05,
  89.     kHIDUsage_X                = 0x30,
  90.     kHIDUsage_Y                = 0x31,
  91.     kHIDUsage_Z                = 0x32,
  92.     kHIDUsage_Rx            = 0x33,
  93.     kHIDUsage_Ry            = 0x34,
  94.     kHIDUsage_Rz            = 0x35,
  95.     kHIDUsage_Slider        = 0x36,
  96.     kHIDUsage_Dial            = 0x37,
  97.     kHIDUsage_Wheel            = 0x38,
  98.     kHIDUsage_HatSwitch        = 0x39,
  99.     
  100.     kHIDPage_Simulation        = 2,
  101.     kHIDUsage_Rudder        = 0xBA,
  102.     kHIDUsage_Throttle        = 0xBB,
  103.  
  104.     kHIDPage_Button            = 9
  105. };
  106.  
  107. // these constants are used to describe specific values for an element (a usbElementKey)
  108. enum
  109. {
  110.     // it is important that all buttons come first and start at 1
  111.     kUSB_button1_element = 1,
  112.     kUSB_button2_element,
  113.     kUSB_button3_element,
  114.     kUSB_button4_element,
  115.     kUSB_button5_element,
  116.     kUSB_button6_element,
  117.     kUSB_button7_element,
  118.     kUSB_button8_element,
  119.     kUSB_button9_element,
  120.     kUSB_button10_element,
  121.     kUSB_button11_element,
  122.     kUSB_button12_element,
  123.     kUSB_button13_element,
  124.     kUSB_button14_element,
  125.     kUSB_button15_element,
  126.     kUSB_button16_element,
  127.     kUSB_trigger_element,
  128.     kUSB_buttonStart_element,
  129.     kUSB_buttonSelect_element,
  130.     kUSB_povhat_element,
  131.     kUSB_povhat4_element,
  132.     kUSB_dpad_element,
  133.     kUSB_dpad4_element,
  134.     kUSB_xaxis_element,
  135.     kUSB_yaxis_element,
  136.     kUSB_throttle_element,
  137.     kUSB_rudder_element,
  138.     kUSB_trim_element,
  139.     kUSB_gas_element,
  140.     kUSB_brake_element,
  141.     kUSB_axis_element
  142. };
  143.  
  144. enum
  145. {
  146.     kStrListResource_DefaultNames = 128
  147. };
  148.  
  149. enum
  150. {
  151.     kStrList_DefaultNames_Trigger = 1,
  152.     kStrList_DefaultNames_LeftTrigger,
  153.     kStrList_DefaultNames_RightTrigger,
  154.     kStrList_DefaultNames_LeftIndexTop,
  155.     kStrList_DefaultNames_LeftIndexBottom,
  156.     kStrList_DefaultNames_RightIndexTop,
  157.     kStrList_DefaultNames_RightIndexBottom,
  158.     kStrList_DefaultNames_ThumbLeftButton,
  159.     kStrList_DefaultNames_ThumbCenterButton,
  160.     kStrList_DefaultNames_ThumbRightButton,
  161.     kStrList_DefaultNames_ThumbTopButton,
  162.     kStrList_DefaultNames_ThumbBottomButton,
  163.     kStrList_DefaultNames_AButton,
  164.     kStrList_DefaultNames_BButton,
  165.     kStrList_DefaultNames_CButton,
  166.     kStrList_DefaultNames_DButton,
  167.     kStrList_DefaultNames_EButton,
  168.     kStrList_DefaultNames_FButton,
  169.     kStrList_DefaultNames_XButton,
  170.     kStrList_DefaultNames_YButton,
  171.     kStrList_DefaultNames_ZButton,
  172.     kStrList_DefaultNames_MButton,
  173.     kStrList_DefaultNames_TAButton,
  174.     kStrList_DefaultNames_TBButton,
  175.     kStrList_DefaultNames_F1Button,
  176.     kStrList_DefaultNames_F2Button,
  177.     kStrList_DefaultNames_F3Button,
  178.     kStrList_DefaultNames_F4Button,
  179.     kStrList_DefaultNames_F5Button,
  180.     kStrList_DefaultNames_F6Button,
  181.     kStrList_DefaultNames_F7Button,
  182.     kStrList_DefaultNames_F8Button,
  183.     kStrList_DefaultNames_YellowButton,
  184.     kStrList_DefaultNames_RedButton,
  185.     kStrList_DefaultNames_GreenButton,
  186.     kStrList_DefaultNames_BlueButton,
  187.     kStrList_DefaultNames_StartButton,
  188.     kStrList_DefaultNames_SelectButton,
  189.     kStrList_DefaultNames_ShiftButton,
  190.     kStrList_DefaultNames_LeftShiftButton,
  191.     kStrList_DefaultNames_RightShiftButton,
  192.     kStrList_DefaultNames_SensorButton,
  193.     kStrList_DefaultNames_Button1,
  194.     kStrList_DefaultNames_Button2,
  195.     kStrList_DefaultNames_Button3,
  196.     kStrList_DefaultNames_Button4,
  197.     kStrList_DefaultNames_Button5,
  198.     kStrList_DefaultNames_Button6,
  199.     kStrList_DefaultNames_Button7,
  200.     kStrList_DefaultNames_Button8,
  201.     kStrList_DefaultNames_Button9,
  202.     kStrList_DefaultNames_Button10,
  203.     kStrList_DefaultNames_Button11,
  204.     kStrList_DefaultNames_Button12,
  205.     kStrList_DefaultNames_Button13,
  206.     kStrList_DefaultNames_Button14,
  207.     kStrList_DefaultNames_Button15,
  208.     kStrList_DefaultNames_Button16,
  209.     kStrList_DefaultNames_Button,
  210.     kStrList_DefaultNames_POVHat,
  211.     kStrList_DefaultNames_DPad,
  212.     kStrList_DefaultNames_XAxis,
  213.     kStrList_DefaultNames_YAxis,
  214.     kStrList_DefaultNames_XTilt,
  215.     kStrList_DefaultNames_YTilt,
  216.     kStrList_DefaultNames_Twist,
  217.     kStrList_DefaultNames_Throttle,
  218.     kStrList_DefaultNames_Trim,
  219.     kStrList_DefaultNames_Rudder,
  220.     kStrList_DefaultNames_Axis,
  221.     kStrList_DefaultNames_Wheel,
  222.     kStrList_DefaultNames_Gas,
  223.     kStrList_DefaultNames_Brake,
  224.     kStrList_DefaultNames_Error
  225. };
  226.  
  227. enum
  228. {
  229.     kButtonElement    = 1,
  230.     kValueElement    = 2
  231. };
  232.  
  233. struct    HIDElement
  234. {
  235.     UInt32        type;
  236.     UInt32        capsIndex;
  237.     HIDUsage    usagePage;
  238.     HIDUsage    usage;
  239.     UInt32        key;
  240.     SInt32        min;
  241.     SInt32        max;
  242.     SInt32        stringIndex;
  243. };
  244. typedef struct HIDElement HIDElement;
  245.  
  246. HIDCaps                gHIDCaps;
  247. HIDButtonCaps *        gHIDButtonCaps;
  248. HIDValueCaps *        gHIDValueCaps;
  249. HIDElement *        gHIDElements;
  250. UInt32                gHIDElementCount = 0;
  251.  
  252. enum { kMaxReportDescSize        = 1024 };
  253. UInt8                            gReportDesc[kMaxReportDescSize];
  254. UInt32                            gReportDescLength;
  255.  
  256. HIDPreparsedDataRef                gPreparsedDataRef;
  257. HIDPreparsedData                gPreparsedData;
  258. UInt32                            gMaxUsageListLength = 0;
  259. HIDUsageAndPage *                gPreviousDownButtons = nil;
  260. HIDUsageAndPage *                gCurrentDownButtons = nil;
  261.  
  262. // lists of dispatch tables
  263. enum { kMaxDevices        = 128 };
  264.  
  265. UHIDModuleDispatchTablePtr        gUHID_dispatchTables[kMaxDevices];
  266. int                                gUHID_count = 0;
  267. UHIDModuleDispatchTablePtr        gCurrentUHID_dispatchTable;
  268. UHIDModuleConnectionID            gCurrentUHIDModuleConnectionID;
  269.  
  270. USBHIDModuleDispatchTablePtr    gMouse_dispatchTables[kMaxDevices];
  271. int                                gMouse_count = 0;
  272.  
  273. // macros
  274.  
  275. #define VERIFY(x)    if (x) { FailCode(x); return; }
  276.  
  277. #define FAILMSG(x) { FailMsg(x); return; }
  278. #define FAILCODE(x) { FailCode(x); return; }
  279.  
  280. #define FFAILMSG(x) { FailMsg(x); return false; }
  281. #define FFAILCODE(x) { FailCode(x); return false; }
  282.  
  283. // protos
  284.  
  285. void     ShowFourByte(OSType fourByte);
  286.  
  287. void     ExitProc (void);
  288. void     DoHIDTest (void);
  289.  
  290. void    GetButtonCapabilities (void);
  291. void    GetValueCapabilities (void);
  292. void    PrintButtonCapabilities (HIDCaps hidCaps, HIDButtonCaps * hidButtonCaps);
  293. void    PrintValueCapabilities (HIDCaps hidCaps, HIDValueCaps * hidValueCaps);
  294.  
  295. void    ClaimAndInstallHandler (void);
  296. void    RemoveHandlerAndRelease (void);
  297. void     myUniversalInterruptProc(void * theData, UInt32 refcon);
  298.  
  299.  
  300. OSStatus    HidP_PrintAllInputValues
  301.           (UInt32                       iCollection,
  302.           HIDPreparsedDataPtr       ptPreparsedData,
  303.            char                      *psReport,
  304.            int                        iReportLength);
  305.  
  306.  
  307. int safeprintf(const char *format, ...);
  308.  
  309. void PrintPreparsedData (void);
  310. void PrintCollectionItems (UInt32 firstCollection, UInt32 collectionCount, char * indent);
  311. void PrintReportItems (UInt32 firstReportItem, UInt32 reportItemCount, char * indent);
  312. void PrintUsageItems (UInt32 firstUsageItem, UInt32 usageItemCount, char * indent);
  313.  
  314. void        SimulateISpEnumeration (void);
  315. OSStatus     PrintHIDElements (void);
  316. OSStatus     BuildHIDElements (void);
  317. UInt32         CountHIDElements(void);
  318. OSStatus     InitializeHIDElement(HIDElement * hidElement);
  319. SInt32        ParseElementValue (UInt32 inElementIndex, Ptr inBuffer);
  320.  
  321. // code
  322.  
  323. static Boolean Progress(UInt32 inItr, UInt32 inTotal, UInt32 inNumReports, char *string)
  324. {
  325.     UInt32 everyNTimes = inTotal / inNumReports;
  326.     
  327.     if (everyNTimes == 0) { everyNTimes = 1; }
  328.     
  329.     if (inItr == 0) { return false; }
  330.     
  331.     if ((inItr % everyNTimes) == 0)
  332.     {
  333.         UInt32 percent = (inItr * 100) / inTotal;
  334.         sprintf(string, "%d%% [%d of %d]", percent, inItr, inTotal);
  335.         return true;
  336.     }
  337.     
  338.     return false;
  339. }
  340.  
  341. static void InitStep(char *msg)
  342. {
  343.     gStep = 0;
  344.     sprintf(gStepId, "%3d");
  345.     
  346.     if (msg == nil)
  347.     {
  348.         printf("step %s\n", gStepId);
  349.     }
  350.     else
  351.     {
  352.         printf("step %s %s\n",gStepId, msg);
  353.     }
  354. }
  355.  
  356. static void NextStep(char *msg)
  357. {
  358.     long this_app_memory;
  359.     long this_sys_memory;
  360.     static Boolean first_time = true;
  361.     static long last_app_memory;
  362.     static long last_sys_memory;
  363.  
  364.     gStep++;
  365.     sprintf(gStepId, "%3d", gStep);
  366.  
  367.     this_app_memory = FreeMem();
  368.     this_sys_memory = FreeMemSys();
  369.  
  370.     if (first_time)    
  371.     {
  372.         first_time = false;
  373.     }
  374.     else
  375.     {
  376.         long delta_app_memory = last_app_memory - this_app_memory;
  377.         long delta_sys_memory = last_sys_memory - this_sys_memory;
  378.         
  379.         printf("step %s ending app mem = %d sys mem = %d\n", gStepId, this_app_memory, this_sys_memory);
  380.         printf("step %s delta app mem = %d sys mem = %d\n", gStepId, delta_app_memory, delta_sys_memory);
  381.     }
  382.  
  383.     if (msg == nil)
  384.     {
  385.         printf("step %s\n", gStepId);
  386.     }
  387.     else
  388.     {
  389.         printf("step %s %s\n",gStepId, msg);
  390.     }
  391.  
  392.     printf("step %s starting app mem = %d sys mem = %d\n", gStepId, this_app_memory, this_sys_memory);
  393.  
  394.     last_app_memory = this_app_memory;
  395.     last_sys_memory = this_sys_memory;
  396. }
  397.  
  398. static void FailMsg(char *failure)
  399. {
  400.     printf("step %s FAILED reason = %s\n", gStepId, failure);
  401. }
  402.  
  403. static void FailCode(OSStatus errorCode)
  404. {
  405.     printf("step %s FAILED errorCode = %d\n", gStepId, errorCode);
  406. }
  407.  
  408. static void StatusMsg(char *msg)
  409. {
  410.     printf("step %s status msg = %s\n",gStepId, msg);
  411. }
  412.  
  413. void ShowFourByte(OSType fourByte)
  414. {
  415.     putchar(((fourByte & 0xff000000) >> 24));
  416.     putchar(((fourByte & 0x00ff0000) >> 16));
  417.     putchar(((fourByte & 0x0000ff00) >> 8));
  418.     putchar(((fourByte & 0x000000ff) >> 00));
  419. }
  420.  
  421. void main(void)
  422. {
  423.     OSErr                             status = noErr;
  424.     CFragConnectionID                usbConnID;
  425.     USBDeviceRef                    usbDeviceRef;
  426.     CFragSymbolClass                symClass;
  427.     UHIDModuleDispatchTablePtr        uHID_dispatchTable;
  428. //    USBHIDModuleDispatchTablePtr    mouse_dispatchTable;
  429.     UInt16                             vendor;
  430.     UInt16                             product;
  431.     THz                                currentZone;
  432.     
  433.         
  434. #if defined(__MWERKS__)
  435.     // tell SIOUX to shut up
  436.     SIOUXSettings.autocloseonquit = false;
  437.     SIOUXSettings.asktosaveonclose = false;
  438.     SIOUXSettings.columns = 120;
  439.     SIOUXSettings.rows = 70;
  440. #endif
  441.     
  442.     printf("starting up...\n");
  443.     
  444.     printf("searching for universal HID devices\n");
  445.     
  446.     usbDeviceRef = 0;
  447.     while (status == noErr && gUHID_count < kMaxDevices)
  448.     {
  449.         printf ("searching for next device...\n");
  450.         
  451.         status = USBGetNextDeviceByClass (&usbDeviceRef, &usbConnID, kUSBHIDClass, kUSBCompositeSubClass, kUSBNoInterfaceProtocol);
  452.         if (status)
  453.         {
  454.             if (status != kUSBNotFound && status != fnfErr)
  455.                 FailCode (status);
  456.             continue;
  457.         }
  458.         
  459.         printf ("candidate found (connID: %00000008x), searching for symbol...\n", usbConnID);
  460.         
  461.         // need to be in the system zone when we search for the symbol
  462.         currentZone = GetZone ();
  463.         SetZone (SystemZone ());
  464.         status = FindSymbol (usbConnID, "\pTheUHIDModuleDispatchTable", (Ptr *)&uHID_dispatchTable, &symClass);
  465.         SetZone (currentZone);
  466.         
  467.         // if we failed to find it, go on to the next device    
  468.         if (status)
  469.         {
  470.             FailCode (status);
  471.             status = noErr; 
  472.             continue;
  473.         }
  474.         
  475.         printf("symbol found, checking versions...\n");
  476.         
  477.         // version checking
  478.         if (uHID_dispatchTable->dispatchTableCurrentVersion < kOldestCompatableDispatchTableVersion)
  479.         {
  480.             printf ("         DispatchTable current version (%d) too old (%d)\n", 
  481.                 uHID_dispatchTable->dispatchTableCurrentVersion, kOldestCompatableDispatchTableVersion);
  482.             continue;
  483.         }
  484.         if (uHID_dispatchTable->dispatchTableOldestVersion > kCurrentDispatchTableVersion)
  485.         {
  486.             printf ("         DispatchTable oldest version (%d) too new (%d)\n", 
  487.                 uHID_dispatchTable->dispatchTableOldestVersion, kCurrentDispatchTableVersion);
  488.             continue;
  489.         }
  490.         
  491.         gUHID_dispatchTables[gUHID_count++] = uHID_dispatchTable;
  492.     
  493.         (UHIDInstallInterruptProcPtr)(*(uHID_dispatchTable->pUHIDGetDeviceInfo))(kUHIDGetVenderID, &vendor);
  494.         (UHIDInstallInterruptProcPtr)(*(uHID_dispatchTable->pUHIDGetDeviceInfo))(kUHIDGetProductID, &product);
  495.         printf("version check success, valid device (Vender:%0004X Product:%0004X).\n", vendor, product);
  496.     }
  497.     
  498.     while (gUHID_count > 0 && !gShouldQuit)
  499.         DoHIDTest();
  500.     
  501.     printf("quitting...\n");
  502. }
  503.  
  504. void     ExitProc (void)
  505. {
  506.     RemoveHandlerAndRelease ();
  507. }
  508.  
  509. void DoHIDTest (void)
  510. {
  511.     OSErr                             status = noErr;
  512.     UHIDModuleDispatchTablePtr        uHID_dispatchTable;
  513. //    USBHIDModuleDispatchTablePtr    mouse_dispatchTable;
  514.     UInt16                             vendor;
  515.     UInt16                             product;
  516.     int                                index;
  517.     char                             string[256];
  518.  
  519. choosedevice:
  520.     // ••• memory leak here, but who cares for now... (We never dispose of these)
  521.     gHIDElementCount = 0;
  522.     
  523.     printf ("\nChoose a device:\n");
  524.     
  525.     // choice to quit
  526.     printf ("1. Exit\n");
  527.  
  528.     // print out UHID choices
  529.     index = 0;
  530.     while (index < gUHID_count)
  531.     {
  532.         uHID_dispatchTable = gUHID_dispatchTables[index];
  533.         (UHIDInstallInterruptProcPtr)(*(uHID_dispatchTable->pUHIDGetDeviceInfo))(kUHIDGetVenderID, &vendor);
  534.         (UHIDInstallInterruptProcPtr)(*(uHID_dispatchTable->pUHIDGetDeviceInfo))(kUHIDGetProductID, &product);
  535.  
  536.         printf ("%d. Vender:%0004X Product:%0004X\n", index + 2, vendor, product);
  537.         index++;
  538.     }
  539.  
  540.     // • todo • print out mouse choices
  541.  
  542.     // get user choice
  543.     printf ("Selection: ");
  544.     gets (string);
  545.     index = atoi (string);
  546.     printf ("\n");
  547.     
  548.     // handle the quit case
  549.     if (index == 1)
  550.     {
  551.         gShouldQuit = true;
  552.         return;
  553.     }
  554.     
  555.     // setup for this device
  556.     uHID_dispatchTable = gCurrentUHID_dispatchTable = gUHID_dispatchTables[index - 2];
  557.     
  558.     // init the printf double buffer
  559.     gInsertPrintfBuffer = gPrintfBuffer1;
  560.     gFreePrintfBuffer = gPrintfBuffer2;
  561.     gInsertIndex = 0;
  562.     
  563.     // get the max packet size
  564.     gMaxPacketSize = 0;
  565.     (UHIDInstallInterruptProcPtr)(*(uHID_dispatchTable->pUHIDGetDeviceInfo))(kUHIDGetMaxPacketSize, &gMaxPacketSize);
  566.     printf("Max packet size = %d\n", gMaxPacketSize);
  567.     
  568.     printf("Printing the report descriptor\n", status);
  569.  
  570.     // print the HID report descriptor
  571.     gReportDescLength = sizeof (gReportDesc);
  572.     status = (*uHID_dispatchTable->pUHIDGetHIDDescriptor)(kUSBReportDesc, 0, &gReportDescLength, gReportDesc);
  573.     if (status)
  574.         printf("*** Error (%d) on Get Report Descriptor Device\n", status);
  575.     else
  576.         PrintHIDReport(gReportDesc, gReportDescLength);
  577.     
  578.     // setup the HID stuff
  579.     status = HIDOpenReportDescriptor (gReportDesc, gReportDescLength, &gPreparsedDataRef, kHIDFlag_StrictErrorChecking);
  580.     if (status)
  581.         printf("*** Error (%d) on HIDOpenDescriptor (strict error checking) \n", status);
  582.     
  583.     // if error, less error checking on the HID stuff
  584.     if (status)
  585.     {
  586.         status = HIDOpenReportDescriptor (gReportDesc, gReportDescLength, &gPreparsedDataRef, 0);
  587.         if (status)
  588.             printf("*** Error (%d) on HIDOpenDescriptor\n", status);
  589.         else
  590.             printf("HIDOpenDescriptor (lax error checking) succeeded. \n", status);
  591.     }
  592.     
  593.     // allocate our buffers
  594.     gMaxUsageListLength = HIDMaxUsageListLength (kHIDInputReport, 0, gPreparsedDataRef);
  595.     printf("Number of buttons (max usage list length) = %ld\n", gMaxUsageListLength);
  596.     
  597.     gPreviousDownButtons = (HIDUsageAndPage *) NewPtr (gMaxUsageListLength * sizeof (HIDUsageAndPage));
  598.     if (gPreviousDownButtons == nil)
  599.         printf("*** Error (%d) on NewPtr for gPreviousDownButtons\n", MemError());
  600.  
  601.     gCurrentDownButtons = (HIDUsageAndPage *) NewPtr (gMaxUsageListLength * sizeof (HIDUsageAndPage));
  602.     if (gCurrentDownButtons == nil)
  603.         printf("*** Error (%d) on NewPtr for gCurrentDownButtons\n", MemError());
  604.  
  605.     printf("gPreviousDownButtons = %lx, gCurrentDownButtons = %lx\n", gPreviousDownButtons, gCurrentDownButtons);
  606.  
  607. whattoget:
  608.     printf ("1. Exit\n");
  609.     printf ("2. Choose another device\n");
  610.     printf ("3. Get data\n");
  611.     printf ("4. Get button capabilities\n");
  612.     printf ("5. Get value capabilities\n");
  613.     printf ("6. Print preparsed data\n");
  614.     printf ("7. Simulate ISp Enumeration\n");
  615.     
  616.     // get user choice
  617.     printf ("Selection: ");
  618.     gets (string);
  619.     index = atoi (string);
  620.     printf ("\n");
  621.     
  622.     switch (index)
  623.     {
  624.         // exit
  625.         case 1:
  626.             gShouldQuit = true;
  627.             goto close;
  628.         
  629.         case 2:
  630.             goto choosedevice;
  631.         
  632.         case 3:
  633.             break;
  634.         
  635.         case 4:
  636.             GetButtonCapabilities();            
  637.             goto whattoget;
  638.         
  639.         case 5:
  640.             GetValueCapabilities();            
  641.             goto whattoget;
  642.         
  643.         case 6:
  644.             PrintPreparsedData();            
  645.             goto whattoget;
  646.         
  647.         case 7:
  648.             SimulateISpEnumeration();            
  649.             goto whattoget;
  650.         
  651.         default:
  652.             goto whattoget;
  653.     }
  654.  
  655.  
  656. getdata:
  657.  
  658.     printf ("1. Exit\n");
  659.     printf ("2. Previous menu\n");
  660.     printf ("3. Display raw bits as hex\n");
  661.     printf ("4. Display raw bits as binary\n");
  662.     printf ("5. Display parsed buttons\n");
  663.     printf ("6. Display parsed values and buttons\n");
  664.     if (gHIDElementCount > 0)
  665.         printf ("7. Simulate ISp\n");
  666.     
  667.     // get user choice
  668.     printf ("Selection: ");
  669.     gets (string);
  670.     index = atoi (string);
  671.     printf ("\n");
  672.     
  673.     
  674.     // make as binary the default, and use in the unimplemented cases?
  675.     gPrint_AsType = kPrint_AsBinary;
  676.     
  677.     switch (index)
  678.     {
  679.         // exit
  680.         case 1:
  681.             gShouldQuit = true;
  682.             goto close;
  683.         
  684.         case 2:
  685.             goto whattoget;
  686.         
  687.         case 3:
  688.             gPrint_AsType = kPrint_AsHex;
  689.             break;
  690.  
  691.         case 4:
  692.             gPrint_AsType = kPrint_AsBinary;
  693.             break;
  694.  
  695.         case 5:
  696.             gPrint_AsType = kPrint_ParseButtons;
  697.             break;
  698.  
  699.         case 6:
  700.             gPrint_AsType = kPrint_ParseBoth;
  701.             break;
  702.  
  703.         case 7:
  704.             if (gHIDElementCount > 0)
  705.                 gPrint_AsType = kPrint_SimulateISp;
  706.             else
  707.                 goto getdata;
  708.             break;
  709.         
  710.         default:
  711.             goto getdata;
  712.     }
  713.     
  714.     ClaimAndInstallHandler();
  715.     
  716.     // get data
  717.     
  718.     printf("getting data (press command to end)\n");
  719.  
  720.     while (1)
  721.     {
  722.         KeyMap theKeys;
  723.  
  724.         if (gInsertIndex)    // if we have data in the queue, then printf it
  725.         {
  726.             char * temp = gInsertPrintfBuffer;
  727.             
  728.             gInsertPrintfBuffer = gFreePrintfBuffer;    // must do 1st! - atomic switch
  729.             gInsertIndex = 0;                            // _technically_ bad, could possibly miss some data
  730.             
  731.             gFreePrintfBuffer = temp;
  732.             
  733.             printf(temp);                
  734.             fflush(stdout);
  735.         }
  736.  
  737.  
  738.         GetKeys(theKeys);
  739.  
  740.         if ((theKeys[1] & 0x8000))
  741.         {
  742.             break;
  743.         }
  744.         
  745.         SIOUXHandleOneEvent(nil);
  746.       }
  747.     
  748.  
  749.     RemoveHandlerAndRelease ();
  750.  
  751.     
  752.     if (!gShouldQuit)
  753.         goto getdata;
  754. close:
  755.  
  756.     status = HIDCloseReportDescriptor (gPreparsedDataRef);
  757.     if (status)
  758.         printf("*** Error (%d) on HIDCloseDescriptor\n", status);
  759.  
  760.     DisposePtr ((void *) gPreviousDownButtons);
  761.     gPreviousDownButtons = nil;
  762.     
  763.     DisposePtr ((void *) gCurrentDownButtons);
  764.     gCurrentDownButtons = nil;
  765.     
  766.     printf("finished\n\n");
  767. }
  768.  
  769. void    GetButtonCapabilities(void)
  770. {
  771.     OSStatus err = noErr;
  772.     
  773.     HIDCaps                hidCaps;
  774.     HIDButtonCaps *        hidButtonCaps = nil;
  775.  
  776.     // get the overall capabilities of the device
  777.     if (err == noErr)
  778.         err = HIDGetCaps (gPreparsedDataRef, &hidCaps);
  779.  
  780.     // allocate space for button caps
  781.     if (err == noErr)
  782.     {
  783.         hidButtonCaps = (HIDButtonCaps *) NewPtrSysClear(sizeof(HIDButtonCaps) * hidCaps.numberInputButtonCaps);
  784.         if (hidButtonCaps == nil)
  785.         {
  786.             printf ("\n•• Failed to allocate space for ButtonCaps\n");
  787.             err = memFullErr;
  788.         }
  789.     }
  790.  
  791.     // get the button capabilities
  792.     if (err == noErr)
  793.         err = HIDGetButtonCaps (kHIDInputReport, hidButtonCaps, &hidCaps.numberInputButtonCaps, gPreparsedDataRef);
  794.     
  795.     // print what we found
  796.     if (err == noErr)
  797.         PrintButtonCapabilities (hidCaps, hidButtonCaps);
  798.     
  799.     // dispose the memory
  800.     if (hidButtonCaps != nil)
  801.         DisposePtr((LogicalAddress) hidButtonCaps);
  802. }
  803.  
  804. void    GetValueCapabilities (void)
  805. {
  806.     OSStatus err = noErr;
  807.     
  808.     HIDCaps                hidCaps;
  809.     HIDValueCaps *        hidValueCaps = nil;
  810.  
  811.     // get the overall capabilities of the device
  812.     if (err == noErr)
  813.         err = HIDGetCaps (gPreparsedDataRef, &hidCaps);
  814.  
  815.     // allocate space for value caps
  816.     if (err == noErr)
  817.     {
  818.         hidValueCaps = (HIDValueCaps *) NewPtrSysClear(sizeof(HIDValueCaps) * hidCaps.numberInputValueCaps);
  819.         if (hidValueCaps == nil)
  820.         {
  821.             err = memFullErr;
  822.             printf ("\n•• Failed to allocate space for ValueCaps\n");
  823.         }
  824.     }
  825.  
  826.     // get the value capabilities
  827.     if (err == noErr)
  828.         err = HIDGetValueCaps (kHIDInputReport, hidValueCaps, &hidCaps.numberInputValueCaps, gPreparsedDataRef);
  829.  
  830.     // print what we found
  831.     if (err == noErr)
  832.         PrintValueCapabilities (hidCaps, hidValueCaps);
  833.     
  834.     // dispose the memory
  835.     if (hidValueCaps != nil)
  836.         DisposePtr((LogicalAddress) hidValueCaps);
  837. }
  838.  
  839. void    PrintButtonCapabilities (HIDCaps hidCaps, HIDButtonCaps * hidButtonCaps)
  840. {
  841.     UInt32    index;
  842.     UInt32    reportID = 0;
  843.     
  844.     printf("%d buttons (device usage: %X on page: %d)\n", 
  845.         hidCaps.numberInputButtonCaps, 
  846.         hidCaps.usage, 
  847.         hidCaps.usagePage);
  848.     for (index = 0; index < hidCaps.numberInputButtonCaps; index++)
  849.     {
  850.         if (reportID != hidButtonCaps[index].reportID)
  851.         {
  852.             reportID = hidButtonCaps[index].reportID;
  853.             printf("Report ID: %d\n", reportID);
  854.         }
  855.         
  856.         if (hidButtonCaps[index].isRange)
  857.             printf("%X-%X:%d\n", 
  858.                 hidButtonCaps[index].u.range.usageMin, 
  859.                 hidButtonCaps[index].u.range.usageMax, 
  860.                 hidButtonCaps[index].usagePage);
  861.         else
  862.             printf("%X:%d\n", 
  863.                 hidButtonCaps[index].u.notRange.usage, 
  864.                 hidButtonCaps[index].usagePage);
  865.     }
  866.  
  867.     printf("\n\n");
  868. }
  869. void    PrintValueCapabilities (HIDCaps hidCaps, HIDValueCaps * hidValueCaps)
  870. {
  871.     UInt32    index;
  872.     UInt32    reportID = 0;
  873.     
  874.     printf("%d values (device usage:%d on page:%d\n", 
  875.         hidCaps.numberInputValueCaps, 
  876.         hidCaps.usage, 
  877.         hidCaps.usagePage);
  878.     for (index = 0; index < hidCaps.numberInputValueCaps; index++)
  879.     {
  880.         if (reportID != hidValueCaps[index].reportID)
  881.         {
  882.             reportID = hidValueCaps[index].reportID;
  883.             printf("Report ID: %d\n", reportID);
  884.         }
  885.         
  886.         if (hidValueCaps[index].isRange)
  887.             printf("%X-%X:%d\t\t(%d<->%d)\t(%d<->%d)\t\t[%d * %d]\t\t••••\n", 
  888.                 hidValueCaps[index].u.range.usageMin, 
  889.                 hidValueCaps[index].u.range.usageMax, 
  890.                 hidValueCaps[index].usagePage,
  891.                 hidValueCaps[index].logicalMin,
  892.                 hidValueCaps[index].logicalMax,
  893.                 hidValueCaps[index].physicalMin,
  894.                 hidValueCaps[index].physicalMax,
  895.                 hidValueCaps[index].bitSize,
  896.                 hidValueCaps[index].reportCount);
  897.         else
  898.             printf("%X:%d\t\t(%d<->%d)\t(%d<->%d)\t\t[%d * %d]\n", 
  899.                 hidValueCaps[index].u.notRange.usage, 
  900.                 hidValueCaps[index].usagePage,
  901.                 hidValueCaps[index].logicalMin,
  902.                 hidValueCaps[index].logicalMax,
  903.                 hidValueCaps[index].physicalMin,
  904.                 hidValueCaps[index].physicalMax,
  905.                 hidValueCaps[index].bitSize,
  906.                 hidValueCaps[index].reportCount);
  907.  
  908.         if (hidValueCaps[index].reportCount > 1)
  909.             printf("••• Report Count > 1\n");
  910.     }
  911.             
  912.     printf("\n\n");
  913. }
  914.  
  915.  
  916. void    ClaimAndInstallHandler (void)
  917. {
  918.     OSErr                             status = noErr;
  919.     UHIDModuleConnectionID            uHIDModuleConnectionID;
  920.  
  921.     if (gCurrentUHID_dispatchTable == nil)
  922.     {
  923.         printf("*** Error: have not specified a device\n");
  924.         return;
  925.     }
  926.     
  927.     if (gCurrentUHIDModuleConnectionID != 0)
  928.     {
  929.         printf("*** Error: Already have device active\n");
  930.         return;
  931.     }
  932.     
  933.     printf("Claiming the device\n");
  934.  
  935.     // claim the device
  936.     status = (OSStatus) ((UHIDClaimDeviceProcPtr)(*(gCurrentUHID_dispatchTable->pUHIDClaimDevice))
  937.                             (&uHIDModuleConnectionID, 0));
  938.     if (status)
  939.     {
  940.         printf("*** Error (%d) on Claim Device\n", status);
  941.         return;
  942.     }
  943.  
  944.     gCurrentUHIDModuleConnectionID = uHIDModuleConnectionID;
  945.     
  946.     // install the handler
  947.  
  948.     printf("Installing the handler\n");
  949.  
  950.     status = (OSStatus) ((UHIDInstallInterruptProcPtr)(*(gCurrentUHID_dispatchTable->pUHIDInstallInterrupt))
  951.                             (uHIDModuleConnectionID, myUniversalInterruptProc, 0));
  952.     if (status)
  953.     {
  954.         printf("*** Error (%d) on Universal Interrupt Handler install\n", status);
  955.         return;
  956.     }
  957.     
  958.  
  959. }
  960.  
  961. void    RemoveHandlerAndRelease (void)
  962. {
  963.     OSErr                             status = noErr;
  964.     
  965.     if (gCurrentUHID_dispatchTable == nil)
  966.     {
  967.         printf("*** Error have not specified a device\n");
  968.         return;
  969.     }
  970.     
  971.     if (gCurrentUHIDModuleConnectionID == 0)
  972.         return;
  973.     
  974.     // remove the handler
  975.     
  976.     status = (OSStatus) (UHIDInstallInterruptProcPtr)(*(gCurrentUHID_dispatchTable->pUHIDInstallInterrupt))
  977.                             (gCurrentUHIDModuleConnectionID, nil, 0);
  978.     if (status)
  979.          printf("*** Error (%d) on Universal Interrupt Handler remove\n", status);
  980.     
  981.     // release the device
  982.     
  983.     status = (OSStatus) ((UHIDReleaseDeviceProcPtr)(*(gCurrentUHID_dispatchTable->pUHIDReleaseDevice))
  984.                             (gCurrentUHIDModuleConnectionID));
  985.     if (status)
  986.          printf("*** Error (%d) on release device\n", status);
  987.     
  988.     gCurrentUHIDModuleConnectionID = 0;
  989.     
  990. }
  991.  
  992. void myUniversalInterruptProc(void * theData, UInt32 /* refcon */)
  993. {
  994. //#pragma unused refcon
  995.  
  996.     UInt16                i;
  997.     UInt8                *pRawData;
  998.     OSErr                status = noErr;
  999.     UInt32                length;
  1000.     UInt32                index;
  1001.     SInt32                value;
  1002.  
  1003.     pRawData = (UInt8*)theData;
  1004.  
  1005.     switch (gPrint_AsType)
  1006.     {
  1007.         case kPrint_AsHex:
  1008.         case kPrint_AsBinary:
  1009.             for (i = 0; i < gMaxPacketSize; i++)
  1010.             {
  1011.                 switch (gPrint_AsType)
  1012.                 {
  1013.                     case kPrint_AsHex:
  1014.                         safeprintf("$%02X ", pRawData[i]);
  1015.                         break;
  1016.  
  1017.                     case kPrint_AsBinary:
  1018.                         safeprintf("%d%d%d%d%d%d%d%d ", !!(pRawData[i]&0x80), !!(pRawData[i]&0x40), 
  1019.                                                         !!(pRawData[i]&0x20), !!(pRawData[i]&0x10),
  1020.                                                         !!(pRawData[i]&0x08), !!(pRawData[i]&0x04), 
  1021.                                                         !!(pRawData[i]&0x02), !!(pRawData[i]&0x01));
  1022.                         break;
  1023.                 }
  1024.             }
  1025.             break;
  1026.  
  1027.         case kPrint_ParseButtons:
  1028.             length = gMaxUsageListLength;
  1029.  
  1030.             status = HIDGetButtons (kHIDInputReport, 0, gCurrentDownButtons, &length, 
  1031.                                         gPreparsedDataRef, theData, gMaxPacketSize);
  1032.             if (status)
  1033.                 safeprintf("HIDGetButtons error (%d)\n", status);
  1034.                                         
  1035.             safeprintf("%d buttons down:   ", length);
  1036.  
  1037.             for (i = 0; i < length; i++)
  1038.                 safeprintf("%d(%d) ", gCurrentDownButtons[i].usage, gCurrentDownButtons[i].usagePage);
  1039.             break;
  1040.  
  1041.         case kPrint_ParseBoth:
  1042.             status = HidP_PrintAllInputValues (0,(HIDPreparsedDataPtr) gPreparsedDataRef, theData, gMaxPacketSize);
  1043.  
  1044.             if (status)
  1045.                 safeprintf("HidP_PrintAllInputValues error (%d)\n", status);
  1046.             break;
  1047.  
  1048.         case kPrint_SimulateISp:
  1049.             for (index = 0; index < gHIDElementCount; index++)
  1050.             {
  1051.                 value = ParseElementValue (index, theData);
  1052.  
  1053.                 safeprintf("%ld, ", value);
  1054.             }
  1055.             break;
  1056.     }
  1057.  
  1058.     safeprintf("   ");
  1059.  
  1060.     safeprintf("\n");    
  1061. }
  1062.  
  1063. OSStatus    HidP_PrintAllInputValues
  1064.           (UInt32                        iCollection,
  1065.           HIDPreparsedDataPtr       ptPreparsedData,
  1066.            char                      *psReport,
  1067.            int                        iReportLength)
  1068. {
  1069.     HIDCollection *ptCollection;
  1070.     HIDReportItem *ptReportItem;
  1071.     UInt32 iR, iE, iU;
  1072.     SInt32 iValue;
  1073.     UInt32 iStart;
  1074.     UInt32 iReportItem;
  1075.     HIDUsageAndPage tUsageAndPage;
  1076. /*
  1077.  *  Disallow Null Pointers
  1078. */
  1079.     if ((ptPreparsedData == NULL) || (psReport == NULL))
  1080.         return kHIDNullPointerErr;
  1081.     if (ptPreparsedData->hidTypeIfValid != kHIDOSType)
  1082.         return kHIDInvalidPreparsedDataErr;
  1083. /*
  1084.  *  Search only the scope of the Collection specified
  1085.  *  Go through the ReportItems
  1086.  *  Filter on ReportType
  1087. */
  1088.     ptCollection = &ptPreparsedData->collections[iCollection];
  1089.  
  1090. #if 0
  1091. safeprintf ("Collection: count: %d\n", ptCollection->reportItemCount);
  1092. #endif
  1093.  
  1094.     for (iR=0; iR<ptCollection->reportItemCount; iR++)
  1095.     {
  1096.         iReportItem = ptCollection->firstReportItem + iR;
  1097.         ptReportItem = &ptPreparsedData->reportItems[iReportItem];
  1098.  
  1099. #if 0
  1100. safeprintf ("Report Item: Type:%d, Size:%d, Start:%d, Count:%d, %s, %s\n", 
  1101.                     ptReportItem->reportType,
  1102.                     ptReportItem->globals.reportSize,
  1103.                     ptReportItem->startBit,
  1104.                     ptReportItem->globals.reportCount,
  1105.                     (ptReportItem->dataModes & kHIDDataArrayBit) == kHIDDataArray ? "isArray" : "notArray",
  1106.                     (ptReportItem->dataModes & kHIDDataConstantBit) == kHIDDataConstant ? "isConstant" : "notConstant");
  1107. #endif
  1108.  
  1109.  
  1110.         if ((ptReportItem->reportType == kHIDInputReport) &&
  1111.             (ptReportItem->dataModes & kHIDDataConstantBit) != kHIDDataConstant)
  1112.         {
  1113. /*
  1114.  *          Values
  1115. */
  1116.             if (HIDIsVariable(ptReportItem))
  1117.             {
  1118.                 int iUsageItem;
  1119.                 
  1120.                 iStart = ptReportItem->startBit;
  1121.                 iUsageItem = ptReportItem->firstUsageItem;
  1122.                 
  1123.                 // loop for each usage item
  1124.                 for (iU=0; iU<ptReportItem->usageItemCount; iU++)
  1125.                 {
  1126.                     OSStatus status = kHIDSuccess;
  1127.                     HIDP_UsageItem *ptUsageItem;
  1128.                     
  1129.                     ptUsageItem = &ptPreparsedData->usageItems[iU];
  1130.                     
  1131.                     // if range, loop for each usage in range (is this right???)
  1132.                     if (ptUsageItem->isRange && false)    // •• diabled
  1133.                     {
  1134.                         int    iUsageValue, min, max;
  1135.                         
  1136.                         min = ptUsageItem->usageMinimum;
  1137.                         max = ptUsageItem->usageMaximum;
  1138.                         if (max < min)
  1139.                         {
  1140.                             int temp;
  1141.                             temp = min; min = max; max = temp;
  1142.                         }
  1143.                         
  1144.                         for (iUsageValue = min; iUsageValue <= max; iUsageValue++)
  1145.                         {
  1146.                             status = HIDGetData(psReport, iReportLength, iStart,
  1147.                                                    ptReportItem->globals.reportSize, &iValue,
  1148.                                                    ((ptReportItem->globals.logicalMinimum < 0)
  1149.                                                   ||(ptReportItem->globals.logicalMaximum < 0)));
  1150.                             if (status)
  1151.                                 safeprintf ("\nHidP_GetData error = %d\n", status);
  1152.  
  1153.                             iStart += ptReportItem->globals.reportSize;
  1154.             
  1155.                             safeprintf("%d:\t%d (%x) ", iUsageValue, iValue, iValue);
  1156.  
  1157.     /*
  1158.     *                          Try to scale the data
  1159.     */
  1160. #if 0
  1161.                             status = HIDScaleUsageValueIn(ptReportItem,iValue,&iValue);
  1162.                             if (status)
  1163.                                 safeprintf ("\nHidP_ScaleUsageValueIn error = %d\n", status);
  1164.                             else
  1165.                                 safeprintf("[%d (%x)]  ", iValue, iValue);
  1166. #endif
  1167.                         }
  1168.                     }
  1169.                     else // not range
  1170.                     {
  1171.                         status = HIDGetData(psReport, iReportLength, iStart,
  1172.                                                ptReportItem->globals.reportSize, &iValue,
  1173.                                                ((ptReportItem->globals.logicalMinimum < 0)
  1174.                                               ||(ptReportItem->globals.logicalMaximum < 0)));
  1175.                         if (status)
  1176.                             safeprintf ("\nHidP_GetData error = %d\n", status);
  1177.  
  1178.                         iStart += ptReportItem->globals.reportSize;
  1179.         
  1180.                         safeprintf("%d(%d-%d):\t%d (%x) ", 
  1181.                             ptUsageItem->usage, ptUsageItem->usageMinimum, ptUsageItem->usageMinimum, 
  1182.                             iValue, iValue);
  1183.  
  1184. #if 0
  1185. /*
  1186. *                          Try to scale the data
  1187. */
  1188.  
  1189.                         status = HIDScaleUsageValueIn(ptReportItem,iValue,&iValue);
  1190.                         if (status)
  1191.                             safeprintf ("\nHidP_ScaleUsageValueIn error = %d\n", status);
  1192.                         else
  1193.                             safeprintf("[%d (%x)]  ", iValue, iValue);
  1194. #endif                            
  1195.                     }
  1196.                 }
  1197.            }
  1198.  
  1199. /*
  1200.  *          Buttons
  1201. */
  1202.  
  1203.             else    // is button
  1204.             {
  1205.     /*
  1206.      *          Save Arrays and Bitmaps
  1207.     */
  1208.                 iStart = ptReportItem->startBit;
  1209.                 for (iE=0; iE<ptReportItem->globals.reportCount; iE++)
  1210.                 {
  1211.                     OSStatus status = kHIDSuccess;
  1212.                     
  1213.     #if 0
  1214.     safeprintf ("startbits = %d (%x) of report item %d:%d\n", iStart, iStart, iR, iE);
  1215.     #endif
  1216.  
  1217.                     if ((ptReportItem->dataModes & kHIDDataArrayBit) == kHIDDataArray)
  1218.                     {
  1219.                         status = HIDGetData(psReport, iReportLength, iStart, ptReportItem->globals.reportSize, &iValue, false);
  1220.                         if (status)
  1221.                             safeprintf ("\nHidP_GetData error = %d\n", status);
  1222.     #if 0
  1223.                         else
  1224.                             safeprintf ("Value = %d (%x) of array item %d:%d\n", iValue, iValue, iE, iR);
  1225.     #endif
  1226.                         iStart += ptReportItem->globals.reportSize;
  1227.                         HIDUsageAndPageFromIndex((HIDPreparsedDataRef)ptPreparsedData,ptReportItem,ptReportItem->globals.logicalMinimum+iE, &tUsageAndPage);
  1228.                         safeprintf("%d:%d ", tUsageAndPage.usage, tUsageAndPage.usagePage);
  1229.  
  1230.                     }
  1231.                     else
  1232.                     {
  1233.                         iValue = 0;
  1234.                         status = HIDGetData(psReport, iReportLength, iStart, 1, &iValue, false);
  1235.                         if (status)
  1236.                             safeprintf ("\nHidP_GetData error = %d\n", status);
  1237.     #if 0
  1238.                         else
  1239.                             safeprintf ("Value = %d (%x) of item %d:%d\n", iValue, iValue, iE, iR);
  1240.     #endif
  1241.                             
  1242.                         iStart++;
  1243.                         if (iValue != 0)
  1244.                         {
  1245.                             HIDUsageAndPageFromIndex((HIDPreparsedDataRef)ptPreparsedData,ptReportItem,ptReportItem->globals.logicalMinimum+iE,&tUsageAndPage);
  1246.                             safeprintf("%d:%d ", tUsageAndPage.usage, tUsageAndPage.usagePage);
  1247.                         }
  1248.                     }
  1249.                 }
  1250.             }
  1251.         }
  1252.     }
  1253.     return kHIDSuccess;
  1254. }
  1255.  
  1256.  
  1257. int safeprintf(const char *format, ...)
  1258. {
  1259.     va_list arglist;
  1260.     int return_value = 0;
  1261.     long len;
  1262.     
  1263.     va_start(arglist, format);
  1264.     return_value= vsprintf(&gInsertPrintfBuffer[gInsertIndex], format, arglist);
  1265.     va_end(arglist);
  1266.     
  1267.     len = strlen(&gInsertPrintfBuffer[gInsertIndex]);
  1268.     
  1269.     if (gInsertIndex + len < kPrintfBufferSize)
  1270.         gInsertIndex += len;
  1271.  
  1272.     return return_value;
  1273. }
  1274.  
  1275. void PrintPreparsedData (void)
  1276. {
  1277.     HIDPreparsedDataPtr        parsedData = (HIDPreparsedDataPtr) gPreparsedDataRef;
  1278.     char                    indent[] = "  ";
  1279.     
  1280.     printf ("\n_Collections_\n");
  1281.     PrintCollectionItems(0, parsedData->collectionCount, indent);
  1282.  
  1283.     printf ("\n_ReportItems_\n");
  1284.     PrintReportItems(0, parsedData->reportItemCount, indent);
  1285.  
  1286.     printf ("\n_UsageItems_\n");
  1287.     PrintUsageItems(0, parsedData->usageItemCount, indent);
  1288.  
  1289.     printf ("\n_StringItems_: %d items\n", parsedData->stringItemCount);
  1290.  
  1291.     printf ("\n_DesigItems_: %d items\n", parsedData->desigItemCount);
  1292.     
  1293.     if (parsedData->stringItemCount > 0 || parsedData->desigItemCount > 0)
  1294.         printf ("••• Wow, it has strings or physical designators!\n");
  1295.     
  1296.     printf ("\n\n");
  1297. }
  1298.  
  1299. void PrintCollectionItems (UInt32 firstCollection, UInt32 collectionCount, char * indent)
  1300. {
  1301.     HIDPreparsedDataPtr        parsedData = (HIDPreparsedDataPtr) gPreparsedDataRef;
  1302.     unsigned                 index, start, end;
  1303.     char                    subIndent[32];
  1304.     
  1305.     sprintf (subIndent, "\t%s", indent);
  1306.     
  1307.     start = firstCollection;
  1308.     end = start + collectionCount;
  1309.     
  1310.     if (end > parsedData->collectionCount)
  1311.     {
  1312.         printf ("%s•••!!!collection integrity error! (%d, %d)\n", indent, end, parsedData->collectionCount);
  1313.         return;
  1314.     }
  1315.     else for (index = start; index < end; index++)
  1316.     {
  1317.         printf ("%sCollection (%X): %d (parent:%d, children:%d, firstChild:%d, nextSibling:%d)\n", 
  1318.             indent,
  1319.             index,
  1320.             parsedData->collections[index].data,
  1321.             parsedData->collections[index].parent,
  1322.             parsedData->collections[index].children,
  1323.             parsedData->collections[index].firstChild,
  1324.             parsedData->collections[index].nextSibling);
  1325.         
  1326.         // print usage items in collection
  1327.         PrintUsageItems       (parsedData->collections[index].firstUsageItem, 
  1328.                             parsedData->collections[index].usageItemCount, 
  1329.                             subIndent);
  1330.  
  1331.         // print report items in collection
  1332.         PrintReportItems   (parsedData->collections[index].firstReportItem, 
  1333.                             parsedData->collections[index].reportItemCount, 
  1334.                             subIndent);
  1335.  
  1336.     }
  1337. }
  1338.  
  1339. void PrintReportItems (UInt32 firstReportItem, UInt32 reportItemCount, char * indent)
  1340. {
  1341.     HIDPreparsedDataPtr        parsedData = (HIDPreparsedDataPtr) gPreparsedDataRef;
  1342.     unsigned                 index, start, end;
  1343.     char                    subIndent[32];
  1344.     
  1345.     sprintf (subIndent, "\t%s", indent);
  1346.     
  1347.     start = firstReportItem;
  1348.     end = start + reportItemCount;
  1349.     
  1350.     if (end > parsedData->reportItemCount)
  1351.     {
  1352.         printf ("%s•••!!!report integrity error! (%d, %d)\n", indent, end, parsedData->reportItemCount);
  1353.         return;
  1354.     }
  1355.     else for (index = start; index < end; index++)
  1356.     {
  1357.         printf ("%sReportItem(%d): Page:%d\t(%d<->%d)\t(%d<->%d)\t[%d+(%d*%d)] %s %s\n",
  1358.             indent,
  1359.             index, 
  1360.             parsedData->reportItems[index].globals.usagePage, 
  1361.             parsedData->reportItems[index].globals.logicalMinimum, 
  1362.             parsedData->reportItems[index].globals.logicalMaximum, 
  1363.             parsedData->reportItems[index].globals.physicalMinimum, 
  1364.             parsedData->reportItems[index].globals.physicalMaximum, 
  1365.             parsedData->reportItems[index].startBit, 
  1366.             parsedData->reportItems[index].globals.reportSize, 
  1367.             parsedData->reportItems[index].globals.reportCount,
  1368.             (parsedData->reportItems[index].dataModes & kHIDDataConstantBit) ? "isConstant" : "",
  1369.             (parsedData->reportItems[index].dataModes & kHIDDataArrayBit) ? "isArray" : "");
  1370.  
  1371.         // print usage items in report item
  1372.         PrintUsageItems       (parsedData->reportItems[index].firstUsageItem, 
  1373.                             parsedData->reportItems[index].usageItemCount, 
  1374.                             subIndent);
  1375.  
  1376.         if (parsedData->reportItems[index].stringItemCount > 0 || parsedData->reportItems[index].desigItemCount > 0)
  1377.             printf ("%sWow, it has strings or physical designators!\n", indent);
  1378.     }
  1379. }
  1380.  
  1381. void PrintUsageItems (UInt32 firstUsageItem, UInt32 usageItemCount, char * indent)
  1382. {
  1383.     HIDPreparsedDataPtr        parsedData = (HIDPreparsedDataPtr) gPreparsedDataRef;
  1384.     unsigned                 index, start, end;
  1385.  
  1386.     start = firstUsageItem;
  1387.     end = start + usageItemCount;
  1388.     
  1389.     if (end > parsedData->usageItemCount)
  1390.     {
  1391.         printf ("%s•••!!!usage integrity error! (%d, %d)\n", indent, end, parsedData->usageItemCount);
  1392.         return;
  1393.     }
  1394.     else for (index = start; index < end; index++)
  1395.     {
  1396.         if (parsedData->usageItems[index].isRange)
  1397.             printf ("%sUsage(%X): %d-%d\n", indent, index, 
  1398.                 parsedData->usageItems[index].usageMinimum, 
  1399.                 parsedData->usageItems[index].usageMaximum);
  1400.         else
  1401.             printf ("%sUsage(%d): %d\n", indent, index, parsedData->usageItems[index].usage);
  1402.     }
  1403. }
  1404.  
  1405. void SimulateISpEnumeration (void)
  1406. {
  1407.     OSStatus             err = noErr;
  1408.     UInt32                count;
  1409.  
  1410.  
  1411.     // get the overall capabilities of the device
  1412.     if (err == noErr)
  1413.         err = HIDGetCaps (gPreparsedDataRef, &gHIDCaps);
  1414.  
  1415.     // ••• for now, only work with devices that appear to be a joystick or gamepad
  1416.     if (err == noErr)
  1417.     {
  1418.         if (gHIDCaps.usagePage != kHIDPage_Generic ||
  1419.             (gHIDCaps.usage != kHIDUsage_Joystick && gHIDCaps.usage != kHIDUsage_Gamepad))
  1420.         {
  1421.             printf("•• matched to non-joystick, non-gamepad... bailing out\n");
  1422.             err = fnfErr;
  1423.         }
  1424.     }
  1425.     
  1426.     // allocate space for button caps
  1427.     if (err == noErr)
  1428.     {
  1429.         gHIDButtonCaps = (HIDButtonCaps *) NewPtrSysClear(sizeof(HIDButtonCaps) * gHIDCaps.numberInputButtonCaps);
  1430.         if (gHIDButtonCaps == nil) printf("•• could not allocate space for buttonCaps\n");
  1431.         if (gHIDButtonCaps == nil) err = memFullErr;
  1432.     }
  1433.  
  1434.     // get the button capabilities
  1435.     if (err == noErr)
  1436.     {
  1437.         count = gHIDCaps.numberInputButtonCaps;
  1438.         err = HIDGetButtonCaps (kHIDInputReport, gHIDButtonCaps, &gHIDCaps.numberInputButtonCaps, gPreparsedDataRef);
  1439.         
  1440.         if (count > gHIDCaps.numberInputButtonCaps)
  1441.             printf ("•• number of button caps increased! (%d->%d)\n", gHIDCaps.numberInputButtonCaps, count);
  1442.         else
  1443.             gHIDCaps.numberInputButtonCaps = count;
  1444.     }
  1445.  
  1446.     // allocate space for value caps
  1447.     if (err == noErr)
  1448.     {
  1449.         gHIDValueCaps = (HIDValueCaps *) NewPtrSysClear(sizeof(HIDValueCaps) * gHIDCaps.numberInputValueCaps);
  1450.         if (gHIDValueCaps == nil) printf("•• could not allocate space for valueCaps\n");
  1451.         if (gHIDValueCaps == nil) err = memFullErr;
  1452.     }
  1453.  
  1454.     // get the value capabilities
  1455.     if (err == noErr)
  1456.         err = HIDGetValueCaps (kHIDInputReport, gHIDValueCaps, &gHIDCaps.numberInputValueCaps, gPreparsedDataRef);
  1457.     
  1458.     // build HID elements
  1459.     if (err == noErr)
  1460.         err = BuildHIDElements ();
  1461.  
  1462.     // print HID elements
  1463.     if (err == noErr)
  1464.         err = PrintHIDElements ();
  1465.     
  1466.     // report error
  1467.     if (err)
  1468.         printf ("•• error = %d\n", err);
  1469. }
  1470.  
  1471. OSStatus PrintHIDElements (void)
  1472. {
  1473.     UInt32    index;
  1474.     
  1475.     printf ("\nHIDElements (%d):\n", gHIDElementCount);
  1476.     for (index = 0; index < gHIDElementCount; index++)
  1477.     {
  1478.         switch (gHIDElements[index].type)
  1479.         {
  1480.             case kButtonElement:
  1481.                 printf ("%2.2d:Button (%d): %X:%d, key:%d, (%d<->%d), str:%d\n",
  1482.                     index,
  1483.                     gHIDElements[index].capsIndex,
  1484.                     gHIDElements[index].usage,
  1485.                     gHIDElements[index].usagePage,
  1486.                     gHIDElements[index].key,
  1487.                     gHIDElements[index].min,
  1488.                     gHIDElements[index].max,
  1489.                     gHIDElements[index].stringIndex
  1490.                     );
  1491.                 break;
  1492.                 
  1493.             case kValueElement:
  1494.                 printf ("%2.2d:Value (%d): %X:%d, key:%d, (%d<->%d), str:%d\n",
  1495.                     index,
  1496.                     gHIDElements[index].capsIndex,
  1497.                     gHIDElements[index].usage,
  1498.                     gHIDElements[index].usagePage,
  1499.                     gHIDElements[index].key,
  1500.                     gHIDElements[index].min,
  1501.                     gHIDElements[index].max,
  1502.                     gHIDElements[index].stringIndex
  1503.                     );
  1504.                 break;
  1505.         }
  1506.     }
  1507.     
  1508.     printf ("\n");
  1509.     
  1510.     return noErr;
  1511. }
  1512.  
  1513. OSStatus BuildHIDElements (void)
  1514. {
  1515.     OSStatus             err = noErr;
  1516.     OSStatus             initErr;
  1517.     UInt32                 hidElementIndex = 0;
  1518.     UInt32                 valueIndex;
  1519.     UInt32                 buttonIndex;
  1520.     HIDUsage             usage;
  1521.     
  1522.     // allocate space for HID elements
  1523.     if (err == noErr)
  1524.     {
  1525.         gHIDElementCount = CountHIDElements();
  1526.         gHIDElements = (HIDElement *) NewPtrSysClear(sizeof(HIDElement) * gHIDElementCount);
  1527.         if (gHIDElements == nil) printf("•• could not allocate space for HIDElements\n");
  1528.         if (gHIDElements == nil) err = memFullErr;
  1529.     }
  1530.  
  1531.     // add all values to the elements
  1532.     if (err == noErr)
  1533.         for (valueIndex = 0; valueIndex < gHIDCaps.numberInputValueCaps; valueIndex++)
  1534.         {
  1535.             HIDElement hidElement;
  1536.  
  1537.             if (gHIDValueCaps[valueIndex].reportCount != 1)
  1538.                 printf("BuildHIDElements: value caps reportCount is not 1!\n");
  1539.                 
  1540.             if (gHIDValueCaps[valueIndex].isRange)
  1541.                 printf("BuildHIDElements: value caps is range!\n");
  1542.  
  1543.             hidElement.type = kValueElement;
  1544.             hidElement.capsIndex = valueIndex;
  1545.             hidElement.usagePage = gHIDValueCaps[valueIndex].usagePage;
  1546.             hidElement.min = gHIDValueCaps[valueIndex].logicalMin;
  1547.             hidElement.max = gHIDValueCaps[valueIndex].logicalMax;
  1548.             
  1549.             // NOTE: no devices I can find have values that are ranges, so this code may not be right!
  1550.             if (gHIDValueCaps[valueIndex].isRange)
  1551.             {
  1552.                 for       (usage = gHIDValueCaps[valueIndex].u.range.usageMin;
  1553.                         usage <= gHIDValueCaps[valueIndex].u.range.usageMax;
  1554.                         usage++)
  1555.                 {
  1556.                     hidElement.usage = usage;
  1557.                     initErr = InitializeHIDElement(&hidElement);
  1558.                     
  1559.                     if (initErr == noErr)
  1560.                         gHIDElements[hidElementIndex++] = hidElement;
  1561.                 }
  1562.             }
  1563.             else // notRange
  1564.             {
  1565.                 hidElement.usage = gHIDValueCaps[valueIndex].u.notRange.usage;
  1566.                 initErr = InitializeHIDElement(&hidElement);
  1567.                 
  1568.                 if (initErr == noErr)
  1569.                     gHIDElements[hidElementIndex++] = hidElement;
  1570.             }
  1571.         }
  1572.  
  1573.     // add all buttons to the elements
  1574.     if (err == noErr)
  1575.         for (buttonIndex = 0; buttonIndex < gHIDCaps.numberInputButtonCaps; buttonIndex++)
  1576.         {
  1577.             HIDElement hidElement;
  1578.             hidElement.type = kButtonElement;
  1579.             hidElement.capsIndex = buttonIndex;
  1580.             hidElement.usagePage = gHIDButtonCaps[buttonIndex].usagePage;
  1581.             hidElement.min = 0;
  1582.             hidElement.max = 1;
  1583.             
  1584.             printf("enumerating button (%d)\n", buttonIndex);
  1585.  
  1586.             // most buttons are reported as ranges of usage values
  1587.             if (gHIDButtonCaps[buttonIndex].isRange)
  1588.             {
  1589.                 for       (usage = gHIDButtonCaps[buttonIndex].u.range.usageMin;
  1590.                         usage <= gHIDButtonCaps[buttonIndex].u.range.usageMax;
  1591.                         usage++)
  1592.                 {
  1593.                     hidElement.usage = usage;
  1594.                     initErr = InitializeHIDElement(&hidElement);
  1595.                     
  1596.                     if (initErr == noErr)
  1597.                         gHIDElements[hidElementIndex++] = hidElement;
  1598.                 }
  1599.             }
  1600.             else // notRange
  1601.             {
  1602.                 hidElement.usage = gHIDButtonCaps[buttonIndex].u.notRange.usage;
  1603.                 initErr = InitializeHIDElement(&hidElement);
  1604.                 
  1605.                 if (initErr == noErr)
  1606.                     gHIDElements[hidElementIndex++] = hidElement;
  1607.             }
  1608.         }
  1609.  
  1610.     return err;
  1611. }
  1612.  
  1613. UInt32 CountHIDElements(void)
  1614. {
  1615.     OSStatus             err = noErr;
  1616.     UInt32                 count = 0;
  1617.     UInt32                 valueIndex;
  1618.     UInt32                 buttonIndex;
  1619.     
  1620.     if (err == noErr)
  1621.         for (valueIndex = 0; valueIndex < gHIDCaps.numberInputValueCaps; valueIndex++)
  1622.         {
  1623.             if (gHIDValueCaps[valueIndex].isRange)
  1624.                 count += (gHIDValueCaps[valueIndex].u.range.usageMax - gHIDValueCaps[valueIndex].u.range.usageMin) + 1;
  1625.             else // notRange
  1626.                 count++;
  1627.         }
  1628.  
  1629.     // count all buttons
  1630.     if (err == noErr)
  1631.         for (buttonIndex = 0; buttonIndex < gHIDCaps.numberInputButtonCaps; buttonIndex++)
  1632.         {
  1633.             if (gHIDButtonCaps[buttonIndex].isRange)
  1634.                 count += (gHIDButtonCaps[buttonIndex].u.range.usageMax - gHIDButtonCaps[buttonIndex].u.range.usageMin) + 1;
  1635.             else // notRange
  1636.                 count++;
  1637.         }
  1638.     
  1639.     return count;
  1640. }
  1641.  
  1642. OSStatus InitializeHIDElement(HIDElement * hidElement)
  1643. {
  1644.     OSStatus             err = noErr;
  1645.     SInt32                 stringIndex = -1;
  1646.  
  1647.     switch (hidElement->type)
  1648.     {
  1649.         case kButtonElement:
  1650.             if (hidElement->usagePage != kHIDPage_Button)
  1651.                 printf("InitializeHIDElement: button found not on button page (%d)\n", hidElement->usagePage);
  1652.  
  1653.             if (hidElement->usagePage != kHIDPage_Button)
  1654.                 return kHIDBadParameterErr;
  1655.             
  1656.             switch (hidElement->usage)
  1657.             {
  1658.                 case 1: case 2: case 3: case 4: case 5: case 6: case 7: case 8: 
  1659.                 case 9: case 10: case 11: case 12: case 13: case 14: case 15: case 16:
  1660.                     hidElement->key = kUSB_button1_element + (hidElement->usage - 1);
  1661.                     stringIndex = kStrList_DefaultNames_Button1 + (hidElement->usage - 1);
  1662.                     break;
  1663.                 default:
  1664.                     return kHIDBadParameterErr;
  1665.             }
  1666.             break;
  1667.  
  1668.         case kValueElement:
  1669.             if (hidElement->usagePage == kHIDPage_Generic)
  1670.                 switch (hidElement->usage)
  1671.                 {
  1672.                     case kHIDUsage_X:
  1673.                         hidElement->key = kUSB_xaxis_element;
  1674.                         stringIndex = kStrList_DefaultNames_XAxis;
  1675.                         break;
  1676.  
  1677.                     case kHIDUsage_Y:
  1678.                         hidElement->key = kUSB_yaxis_element;
  1679.                         stringIndex = kStrList_DefaultNames_YAxis;
  1680.                         break;
  1681.  
  1682.                     case kHIDUsage_Z:
  1683.                         hidElement->key = kUSB_axis_element;
  1684.                         stringIndex = kStrList_DefaultNames_Axis;
  1685.                         break;
  1686.  
  1687.                     case kHIDUsage_Rx:
  1688.                         hidElement->key = kUSB_axis_element;
  1689.                         stringIndex = kStrList_DefaultNames_Axis;
  1690.                         break;
  1691.  
  1692.                     case kHIDUsage_Ry:
  1693.                         hidElement->key = kUSB_axis_element;
  1694.                         stringIndex = kStrList_DefaultNames_Axis;
  1695.                         break;
  1696.  
  1697.                     case kHIDUsage_Rz:
  1698.                         hidElement->key = kUSB_rudder_element;
  1699.                         stringIndex = kStrList_DefaultNames_Twist;
  1700.                         break;
  1701.  
  1702.                     case kHIDUsage_Slider:
  1703.                         hidElement->key = kUSB_throttle_element;
  1704.                         stringIndex = kStrList_DefaultNames_Throttle;
  1705.                         break;
  1706.  
  1707.                     case kHIDUsage_Dial:
  1708.                     case kHIDUsage_Wheel:
  1709.                         hidElement->key = kUSB_trim_element;
  1710.                         stringIndex = kStrList_DefaultNames_Trim;
  1711.                         break;
  1712.  
  1713.                     case kHIDUsage_HatSwitch:
  1714.                         hidElement->key = kUSB_povhat_element;
  1715.                         stringIndex = kStrList_DefaultNames_POVHat;
  1716.                         break;
  1717.                 }
  1718.             else if (hidElement->usagePage == kHIDPage_Simulation)
  1719.                 switch (hidElement->usage)
  1720.                 {
  1721.                     case kHIDUsage_Rudder:
  1722.                         hidElement->key = kUSB_rudder_element;
  1723.                         stringIndex = kStrList_DefaultNames_Rudder;
  1724.                         break;
  1725.  
  1726.                     case kHIDUsage_Throttle:
  1727.                         hidElement->key = kUSB_throttle_element;
  1728.                         stringIndex = kStrList_DefaultNames_Throttle;
  1729.                         break;
  1730.                 }
  1731.             break;
  1732.  
  1733.         default:
  1734.             printf("InitializeHIDElement: unknown type (%d)\n", hidElement->type);
  1735.             err = kHIDBadParameterErr;
  1736.             break;
  1737.     }
  1738.     
  1739.     hidElement->stringIndex = stringIndex;
  1740.         
  1741.     return err;
  1742. }
  1743.  
  1744. SInt32 ParseElementValue (UInt32 inElementIndex, Ptr inBuffer)
  1745. {
  1746.     OSStatus         err = noErr;
  1747.     HIDUsage        usageList[kUSB_button16_element];
  1748.     UInt32            usageListSize = kUSB_button16_element;
  1749.     UInt32            index;
  1750.     HIDElement *    hidElement = &gHIDElements[inElementIndex];
  1751.     SInt32            usageValue;
  1752.     
  1753.     switch (hidElement->type)
  1754.     {
  1755.         case kButtonElement:
  1756.             // for now, we'll only look at buttons on the button page
  1757.             err = HIDGetButtonsOnPage  (kHIDInputReport, 
  1758.                                         kHIDPage_Button, 
  1759.                                         0,
  1760.                                         usageList,
  1761.                                         &usageListSize,
  1762.                                         gPreparsedDataRef,
  1763.                                         inBuffer,
  1764.                                         gMaxPacketSize);
  1765.             
  1766.             // confirm we succeeded
  1767.             if (err != noErr && err != kHIDUsageNotFoundErr)
  1768.                 safeprintf ("••ParseElementValue: HIDGetButtonsOnPage failed (%d)", err);
  1769.             if (err != noErr)
  1770.                 break;
  1771.             
  1772.             // walk the returned usage list
  1773.             for (index = 0; index < usageListSize; index++)
  1774.             {
  1775.                 // if our usage is in the usage list, then we are down
  1776.                 if (usageList[index] == hidElement->usage)
  1777.                     return 1;
  1778.             }
  1779.             
  1780.             // we were not in the list, so we are up
  1781.             return 0;
  1782.             
  1783.         case kValueElement:
  1784.             // get the usage value
  1785.             err = HIDGetUsageValue (kHIDInputReport,
  1786.                                     hidElement->usagePage,
  1787.                                     0,    // •• this might be faster if we store collection and pass here
  1788.                                     hidElement->usage,
  1789.                                     &usageValue,
  1790.                                     gPreparsedDataRef,
  1791.                                     inBuffer,
  1792.                                     gMaxPacketSize);
  1793.  
  1794.             // confirm we succeeded
  1795.             if (err != noErr && err != kHIDUsageNotFoundErr)
  1796.                 safeprintf ("••ParseElementValue: HIDGetUsageValue failed (%d)", err);
  1797.             if (err != noErr)
  1798.                 break;
  1799.             
  1800.             // handle dpads
  1801.             if (false && hidElement->key == kUSB_povhat_element)
  1802.             {
  1803.                 if (usageValue < hidElement->min || usageValue > hidElement->max)
  1804.                     usageValue = kISpPadIdle;
  1805.                 else
  1806.                 {
  1807.                     SInt32    normalized = usageValue - hidElement->min;
  1808.                     SInt32    normalizedMax = hidElement->max - hidElement->min;
  1809.                     
  1810.                     // avoid devide by zero
  1811.                     if (normalizedMax == 0) return kISpPadIdle;
  1812.                     
  1813.                     // rescale value
  1814.                     normalized = ((normalized * 7)) / normalizedMax;
  1815.                     switch (normalized)
  1816.                     {
  1817.                         case 0:    usageValue = kISpPadUp;         break;
  1818.                         case 1:    usageValue = kISpPadUpRight;    break;
  1819.                         case 2:    usageValue = kISpPadRight;        break;
  1820.                         case 3:    usageValue = kISpPadDownRight;    break;
  1821.                         case 4:    usageValue = kISpPadDown;        break;
  1822.                         case 5:    usageValue = kISpPadDownLeft;    break;
  1823.                         case 6:    usageValue = kISpPadLeft;        break;
  1824.                         case 7:    usageValue = kISpPadUpLeft;        break;
  1825.  
  1826.                         default:usageValue = kISpPadIdle;        break; // should not get here
  1827.                     }
  1828.                 }
  1829.             }
  1830.             
  1831.             return usageValue;
  1832.     }
  1833.     
  1834.     return 0;
  1835. }
  1836.